#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include "wblib.h"
#include "nuc900_sic.h"

#define CACHE_ON

#define TEST_PORT0

#define SD_TEST
//#define MS_TEST

#define FMI_TEST_SIZE	512 * 128 * 2
__align(4096) UINT8 fmiFlash_Buf[FMI_TEST_SIZE];
__align(4096) UINT8 fmiReadBackBuffer[FMI_TEST_SIZE];


int main()
{
	unsigned int volatile i, sector, data;
	unsigned char *pSrc, *pDst;
	int volatile btime, status;
	WB_PLL_T sysClock;

	sysClock.pll0 = PLL_200MHZ;
	sysClock.pll1 = PLL_133MHZ;
	sysClock.cpu_src = CPU_FROM_PLL0;
	sysClock.ahb_clk = AHB_CPUCLK_1_2;
	sysClock.apb_clk = APB_AHB_1_2;
	sysSetPLLConfig(&sysClock);

#ifdef CACHE_ON
	sysDisableCache();
	sysInvalidCache();
	sysSetMMUMappingMethod(MMU_DIRECT_MAPPING);
	sysEnableCache(CACHE_WRITE_BACK);
#endif

	pSrc = (UINT8 *)((UINT32)fmiFlash_Buf | 0x80000000);
	pDst = (UINT8 *)((UINT32)fmiReadBackBuffer | 0x80000000);

	sysSetTimerReferenceClock (TIMER0, 15000000);
	sysStartTimer (TIMER0, 100, PERIODIC_MODE);

	// set FMI reference clock
	sicIoctl(SIC_SET_CLOCK, 200000, 0, 0);

	data = 0;
	for (i=0; i<FMI_TEST_SIZE; i++)
	{
		*(pSrc+i) = (data + i) & 0xff;
		if (((i+1) % 0xff) == 0)
			data++;
	}

	// initial FMI
	sicOpen();

#ifdef SD_TEST
	memset(pDst, 0, FMI_TEST_SIZE);

#ifdef TEST_PORT0
	sector = sicSdOpen(0);
#else
	sector = sicSdOpen(1);
#endif
	printf("total sectors [%d]\n", sector);

	printf("SD write\n");
	btime = sysGetTicks(TIMER0);
#ifdef TEST_PORT0
	status = sicSdWrite(0, 3000, FMI_TEST_SIZE/512, (unsigned int)pSrc);
#else
	status = sicSdWrite(1, 3000, FMI_TEST_SIZE/512, (unsigned int)pSrc);
#endif
	btime = sysGetTicks(TIMER0) - btime;
	if (btime == 0) btime = 1;

	printf("[%d] SD write speed %d KB/sec [%d]\n", status, (FMI_TEST_SIZE * 100) / (btime * 1024), btime);

	printf("SD read\n");
	btime = sysGetTicks(TIMER0);
#ifdef TEST_PORT0
	status = sicSdRead(0, 3000, FMI_TEST_SIZE/512, (unsigned int)pDst);
#else
	status = sicSdRead(1, 3000, FMI_TEST_SIZE/512, (unsigned int)pDst);
#endif
	btime = sysGetTicks(TIMER0) - btime;
	if (btime == 0) btime = 1;

	printf("[%d] SD read speed %d KB/sec\n", status, (FMI_TEST_SIZE * 100) / (btime * 1024));

	printf("compare\n");
	for (i=0; i<FMI_TEST_SIZE; i++)
	{
		if (*(pSrc+i) != *(pDst+i))
		{
			printf("error!! <%x> Src[%x], Dst[%x]\n", i, *(pSrc+i), *(pDst+i));
			//exit(0);
			break;
		}
	}
#endif

#ifdef MS_TEST
	memset(pDst, 0, FMI_TEST_SIZE);

#ifndef TEST_PORT0
	sector = sicMsOpen(0);
#else
	sector = sicMsOpen(1);
#endif
	printf("total sectors [%d]\n", sector);

	printf("MS write\n");
	btime = sysGetTicks(TIMER0);
#ifndef TEST_PORT0
	status = sicMsWrite(0, 3000, FMI_TEST_SIZE/512, (unsigned int)pSrc);
#else
	status = sicMsWrite(1, 3000, FMI_TEST_SIZE/512, (unsigned int)pSrc);
#endif
	btime = sysGetTicks(TIMER0) - btime;
	if (btime == 0) btime = 1;

	printf("[%d] MS write speed %d KB/sec\n", status, (FMI_TEST_SIZE * 100) / (btime * 1024));

	printf("MS read\n");
	btime = sysGetTicks(TIMER0);
#ifndef TEST_PORT0
	status = sicMsRead(0, 3000, FMI_TEST_SIZE/512, (unsigned int)pDst);
#else
	status = sicMsRead(1, 3000, FMI_TEST_SIZE/512, (unsigned int)pDst);
#endif
	btime = sysGetTicks(TIMER0) - btime;
	if (btime == 0) btime = 1;

	printf("[%d] MS read speed %d KB/sec\n", status, (FMI_TEST_SIZE * 100) / (btime * 1024));


	printf("compare\n");
	for (i=0; i<FMI_TEST_SIZE; i++)
	{
		if (*(pSrc+i) != *(pDst+i))
		{
			printf("error!! <%x> Src[%x], Dst[%x]\n", i, *(pSrc+i), *(pDst+i));
			//exit(0);
			break;
		}
	}
#endif

	printf("finish test..\n");
	return 0;
}

extern unsigned int Image$$ZI$$Limit;

__value_in_regs struct R0_R3 {unsigned heap_base, stack_base, heap_limit, stack_limit;} 
    __user_initial_stackheap(unsigned int R0, unsigned int SP, unsigned int R2, unsigned int SL)
{
    struct R0_R3 config;

    config.heap_base = (unsigned int)&Image$$ZI$$Limit;
    config.stack_base = sysGetSdramSizebyMB()*0x100000; //Stack base;

/*
To place heap_base directly above the ZI area, use:
    extern unsigned int Image$$ZI$$Limit;
    config.heap_base = (unsigned int)&Image$$ZI$$Limit;
(or &Image$$region_name$$ZI$$Limit for scatterloaded images)

To specify the limits for the heap & stack, use e.g:
    config.heap_limit = SL;
    config.stack_limit = SL;
*/

    return config;
}


